GM.Version = "2.4.3"
GM.Name = "DarkRP"
GM.Author = "By Rickster, Updated: Pcwizdan, Sibre, philxyz, [GNC] Matt, Chrome Bolt, FPtje Falco, Eusion, Drakehawke"

CUR = "$"

-- Checking if counterstrike is installed correctly
if table.Count(file.Find("*", "cstrike")) == 0 then
	timer.Create("TheresNoCSS", 10, 0, function()
		for k,v in pairs(player.GetAll()) do
			v:ChatPrint("Counter Strike: Source is incorrectly installed!")
			v:ChatPrint("You need it for DarkRP to work!")
			print("Counter Strike: Source is incorrectly installed!\nYou need it for DarkRP to work!")
		end
	end)
end

-- RP Name Overrides

local meta = FindMetaTable("Player")
meta.SteamName = meta.SteamName or meta.Name
meta.Name = function(self)
	if not IsValid(self) then return "" end
	if GAMEMODE.Config.allowrpnames then
		self.DarkRPVars = self.DarkRPVars or {}
		return self.DarkRPVars.rpname and tostring(self.DarkRPVars.rpname) or self:SteamName()
	else
		return self:SteamName()
	end
end
meta.Nick = meta.Name
meta.GetName = meta.Name
-- End

DeriveGamemode("sandbox")

util.AddNetworkString("DarkRP_InitializeVars")
util.AddNetworkString("DarkRP_DoorData")
util.AddNetworkString("FAdmin_retrievebans")
util.AddNetworkString("DarkRP_keypadData")
util.AddNetworkString("fileReport")

AddCSLuaFile("addentities.lua")
AddCSLuaFile("shared.lua")
AddCSLuaFile("ammotypes.lua")
AddCSLuaFile("cl_init.lua")
AddCSLuaFile("config.lua")


AddCSLuaFile("client/DRPDermaSkin.lua")
AddCSLuaFile("client/help.lua")
AddCSLuaFile("client/helpvgui.lua")
AddCSLuaFile("client/hud.lua")
AddCSLuaFile("client/showteamtabs.lua")
AddCSLuaFile("client/vgui.lua")
AddCSLuaFile("client/cl_statsystem.lua")
AddCSLuaFile("client/hudextend.lua")


AddCSLuaFile("shared/animations.lua")
AddCSLuaFile("shared/commands.lua")
AddCSLuaFile("shared/entity.lua")
AddCSLuaFile("shared/language.lua")
AddCSLuaFile("shared/MakeThings.lua")
AddCSLuaFile("shared/Workarounds.lua")

-- Earthquake Mod addon
resource.AddFile("sound/earthquake.mp3")
util.PrecacheSound("earthquake.mp3")

resource.AddFile("materials/darkrp/DarkRPSkin.png")

DB = DB or {}
GM.Config = GM.Config or {}
GM.NoLicense = GM.NoLicense or {}

-- sv_alltalk must be 0
-- Note, everyone will STILL hear everyone UNLESS rp_voiceradius is 1!!!
-- This will fix the rp_voiceradius not working
game.ConsoleCommand("sv_alltalk 0\n")

include("_MySQL.lua")
include("config.lua")
include("licenseweapons.lua")

include("server/chat.lua")
include("server/admincc.lua")

include("shared/animations.lua")
include("shared/commands.lua")
include("shared/entity.lua")

include("shared/language.lua")
include("shared/MakeThings.lua")
include("shared/Workarounds.lua")

include("shared.lua")
include("addentities.lua")
include("ammotypes.lua")

include("server/data.lua")
include("server/gamemode_functions.lua")
include("server/main.lua")
include("server/player.lua")
include("server/questions.lua")
include("server/util.lua")
include("server/votes.lua")
include("server/statsystem.lua")


-- Falco's prop protection
local BlockedModelsExist = sql.QueryValue("SELECT COUNT(*) FROM FPP_BLOCKEDMODELS;") ~= false
if not BlockedModelsExist then
	sql.Query("CREATE TABLE IF NOT EXISTS FPP_BLOCKEDMODELS('model' TEXT NOT NULL PRIMARY KEY);")
	include("fpp/FPP_DefaultBlockedModels.lua") -- Load the default blocked models
end
AddCSLuaFile("fpp/sh_CPPI.lua")
AddCSLuaFile("fpp/sh_settings.lua")
AddCSLuaFile("fpp/client/FPP_Menu.lua")
AddCSLuaFile("fpp/client/FPP_HUD.lua")
AddCSLuaFile("fpp/client/FPP_Buddies.lua")
AddCSLuaFile("shared/fadmin_darkrp.lua")

include("fpp/sh_settings.lua")
include("fpp/sh_CPPI.lua")
include("fpp/server/FPP_Settings.lua")
include("fpp/server/FPP_Core.lua")
include("fpp/server/FPP_Antispam.lua")
include("shared/fadmin_darkrp.lua")

/*---------------------------------------------------------------------------
Loading modules
---------------------------------------------------------------------------*/
local fol = GM.FolderName.."/gamemode/modules/"
local files, folders = file.Find(fol .. "*", "LUA")
for k,v in pairs(files) do
	include(fol .. v)
end

for _, folder in SortedPairs(folders, true) do
	if folder ~= "." and folder ~= ".." and folder~="hungermod" and folder~="afk" then
		print(folder)
		for _, File in SortedPairs(file.Find(fol .. folder .."/sh_*.lua", "LUA"), true) do
			AddCSLuaFile(fol..folder .. "/" ..File)
			include(fol.. folder .. "/" ..File)
		end

		for _, File in SortedPairs(file.Find(fol .. folder .."/sv_*.lua", "LUA"), true) do
			include(fol.. folder .. "/" ..File)
		end

		for _, File in SortedPairs(file.Find(fol .. folder .."/cl_*.lua", "LUA"), true) do
			AddCSLuaFile(fol.. folder .. "/" ..File)
		end
	end
end

local function getNewFileName()
	replaceChar = "_"

	local newname = string.Replace(os.date(), "/", "-")
	newname = string.Replace(newname, ":", "_")
	return newname
end

function saveReportToFile(Report, typeID)
	file.CreateDir("server_reports")
	local fileName = getNewFileName()
	if typeID==1 then
		//file.CreateDir("server_reports/admin_abuse")
		file.Write("server_reports/admin_abuse/" .. fileName .. ".txt", Report)
	elseif typeID == 2 then
		file.CreateDir("server_reports/ban_request")
		file.Write("server_reports/ban_request/" .. fileName .. ".txt", Report)
	elseif typeID == 3 then
		file.CreateDir("server_reports/suggestion")
		file.Write("server_reports/suggestion/" .. fileName .. ".txt", Report)
	elseif typeID == 4 then
		file.CreateDir("server_reports/bug_report")
		file.Write("server_reports/bug_report/" .. fileName .. ".txt", Report)
	end
end

net.Receive("fileReport", function(len, ply)
	if (not ply:GetTable().LastReport) or ply:GetTable().LastReport<CurTime()-120 then
		saveReportToFile(net.ReadString(), net.ReadInt(4))
		ply:GetTable().LastReport = CurTime()
		GAMEMODE:Notify( ply, 1, 4, "Thank you, your report has been saved." )
	else
		GAMEMODE:Notify( ply, 1, 4, "You're filing reports too fast, please try again in about 5 minutes" )
	end
end )

function MakeNPCText(ent, text)
	local textplate = ents.Create("npcheadtext")
	textplate:SetModel("models/hunter/plates/plate1x1.mdl'")
	textplate:SetPos(ent:GetPos() + ent:GetAngles():Up()*95)
	textplate:SetAngles(Angle(0,ent:GetAngles().yaw, 0))
	textplate:SetMaterial("Models/effects/vol_light001")
	textplate:Spawn()
	textplate:SetParent(ent)
	textplate:SetCollisionGroup( COLLISION_GROUP_WORLD )
	textplate:SetText(text)
end

function doWorkSon(ent,dmginfo)
    if dmginfo:GetInflictor():IsNPC() and ent:IsPlayer() then
    	dmginfo:ScaleDamage(math.random(ent:Health()/11,22))
    	//GAMEMODE:AddNotify("You're hit!  Consider buying some armor from a medic!", NOTIFY_GENERIC, 15)//ent:PrintMessage (3, "You hit "..inflictor.." for "..dmginfo:GetDamage().." damage!\n")
   end
end
 
hook.Add("EntityTakeDamage","takedamage",doWorkSon)

local function GetAvailableVehicles(ply)
	if not ply:IsAdmin() then return end
	ServerLog("Available vehicles for custom vehicles:" .. "\n")
	print("Available vehicles for custom vehicles:")
	for k,v in pairs(list.Get("Vehicles")) do
		ServerLog("\""..k.."\"" .. "\n")
		print("\""..k.."\"")
	end
end
concommand.Add("rp_getvehicles_sv", GetAvailableVehicles)

/*---------------------------------------------------------------------------
Registering numpad data
---------------------------------------------------------------------------*/
local oldNumpadUp = numpad.OnUp
local oldNumpadDown = numpad.OnDown

function numpad.OnUp(ply, key, name, ent, ...)
	numpad.OnUpItems = numpad.OnUpItems or {}
	table.insert(numpad.OnUpItems, {ply = ply, key = key, name = name, ent = ent, arg = {...}})

	return oldNumpadUp(ply, key, name, ent, ...)
end

function numpad.OnDown(ply, key, name, ent, ...)
	numpad.OnDownItems = numpad.OnDownItems or {}
	table.insert(numpad.OnDownItems, {ply = ply, key = key, name = name, ent = ent, arg = {...}})

	return oldNumpadDown(ply, key, name, ent, ...)
end

function setupNetReceives()
	util.AddNetworkString("giveVehicleScript")
	util.AddNetworkString("sendVehicleScript")
end

hook.Add("Initialize", "setupNetReceives", setupNetReceives)

net.Receive("giveVehicleScript", function(length , ply)
	ent = net.ReadEntity()

	net.Start("sendVehicleScript")
		local vehTable = ent.VehicleTable or {Name = "unknown", vehiclescript = "unknown"}
		net.WriteTable(vehTable)
	net.Send(ply)
end)

print(" ---- Passanger Mod v1.0 Initialized! ----- ")
print(" ------- Passanger Mod by CaMoTraX  -------- ")

function SetupCarSeats( ply, vehicle )
	vehicle:KeysLock()
	local localpos = vehicle:GetPos() 
	local localang = vehicle:GetAngles()
	
	local SeatName = vehicle.VehicleTable.SeatType
	
	local seatdata = list.Get( "Vehicles" )[ "Seat_Airboat" ]
	
	vehicle.Seats = {}

	vehicle.VehicleTable.VC_ExtraSeats = vehicle.VehicleTable.VC_ExtraSeats or {}
	
	for a,b in pairs(vehicle.VehicleTable.VC_ExtraSeats) do
		local SeatPos = localpos + ( localang:Forward() * b.Pos.x) + ( localang:Right() * b.Pos.y) + ( localang:Up() * b.Pos.z)
		local Seat = ents.Create( "prop_vehicle_prisoner_pod" )
		
		local SeatPos = localpos + ( localang:Forward() * b.Pos.x) + ( localang:Right() * b.Pos.y) + ( localang:Up() * b.Pos.z)
		local Seat = ents.Create( "prop_vehicle_prisoner_pod" )
		Seat:SetModel( seatdata.Model )
		Seat:SetKeyValue( "vehiclescript" , "scripts/vehicles/prisoner_pod.txt" )
		Seat:SetAngles( localang + b.Ang )
		Seat:SetPos( vehicle:LocalToWorld(b.Pos) )
			Seat:Spawn()
			Seat:Activate()
			
			if b.Hide then
				Seat:SetColor(Color(255,255,255,0))
				Seat:SetRenderMode( RENDERMODE_TRANSALPHA )
			end
			
			constraint.Weld(Seat, vehicle, 0,0,0,0)
			Seat:SetParent(vehicle)
			
			if ( seatdata.KeyValues ) then
					for k, v in pairs( seatdata.KeyValues ) do
					Seat:SetKeyValue( k, v )
					end		
			end
				
			
		Seat.VehicleName = "Jeep Seat"
		Seat.ClassOverride = "prop_vehicle_prisoner_pod"
		Seat.locked = false
		Seat:DeleteOnRemove( vehicle )
		table.insert(vehicle.Seats, Seat)
		----------- Replace the position with the ent so we can find it later.
		--vehicle.VehicleTable.Passengers[a].Ent = Seat
		
		if !(timer.Exists("Taxi_Timer")) then
			timer.Create("TaxiTimer", 5, 0, function()
				for k, v in pairs(player.GetAll()) do
					if v:InVehicle() && IsValid( v:GetVehicle() ) && !(v:GetVehicle():GetClass() == "prop_vehicle_prisoner_pod") && v:Team() == TEAM_TDRIVER && v:GetVehicle():GetPhysicsObject():GetVelocity():Length() > 50 then
						local car = v:GetVehicle()
						
						for _, seat in pairs(car.Seats) do
							if IsValid(seat:GetDriver()) && !(seat:GetDriver() == v) then
								if seat:GetDriver():CanAfford(2) then
									seat:GetDriver():AddMoney(-2)
									v:AddMoney(2)
								else
									GAMEMODE:Notify( v, 1, 4, seat:GetDriver():Nick() .. " could not pay the $2!" )
								end
							end
						end
					end
				end
			end)
		end
		
	end
end
hook.Add( "PlayerSpawnedVehicle", "SpawnedVehicle", SetupCarSeats )
/*
function passengerSeatEnter(ply, ent)
	//return true
	if ent:IsVehicle() and ent.VehicleTable and ent.VehicleTable.VC_ExtraSeats and ent:GetDriver():IsPlayer() then
		for k,v in pairs(ent.Seats) do
			if v:IsVehicle() and (not v:GetDriver():IsPlayer()) then
				GAMEMODE:PlayerUse(ply,v)
			end
		end
	elseif ent:IsVehicle() and (not ent:GetDriver():IsPlayer()) then
		return true
	end
end
hook.Add("PlayerUse", "passengerseatenter", passengerSeatEnter)*/

local function LockAllSeats( ply )
	if !(IsValid( ply )) then return end
	if !(ply:InVehicle()) then return end
	if ply:GetVehicle():GetClass() == "prop_vehicle_prisoner_pod" then return end
	
	local v = ply:GetVehicle()
	
	for _, seat in pairs(v.Seats) do
		seat.locked = true
	end
	ply:ChatPrint("All seats locked.")
end
AddChatCommand("/lock", LockAllSeats)
AddChatCommand("/Lock", LockAllSeats)
AddChatCommand("!Lock", LockAllSeats)
AddChatCommand("!lock", LockAllSeats)

local function UnLockAllSeats( ply )
	if !(IsValid( ply )) then return end
	if !(ply:InVehicle()) then return end
	if ply:GetVehicle():GetClass() == "prop_vehicle_prisoner_pod" then return end
	
	local v = ply:GetVehicle()
	
	for _, seat in pairs(v.Seats) do
		seat.locked = false
	end
	ply:ChatPrint("All seats unlocked.")
end
AddChatCommand("/unlock", UnLockAllSeats)
AddChatCommand("/Unlock", UnLockAllSeats)
AddChatCommand("!unlock", UnLockAllSeats)
AddChatCommand("!Unlock", UnLockAllSeats)

local function EjectPassengers(ply)
	if !(IsValid( ply )) then return end
	if !(ply:InVehicle()) then return end
	if ply:GetVehicle():GetClass() == "prop_vehicle_prisoner_pod" then return end
	
	local v = ply:GetVehicle()
	
	for _, seat in pairs(v.Seats) do
		if IsValid(seat:GetDriver()) && !(seat:GetDriver() == ply) then
			seat:GetDriver():ExitVehicle()
		end
	end
		
	return ""
end
AddChatCommand("/eject", EjectPassengers)
AddChatCommand("!eject", EjectPassengers)
AddChatCommand("/Eject", EjectPassengers)
AddChatCommand("!Eject", EjectPassengers)

local function HonkHorn( player,cmd,arg )
if player:InVehicle() then
local vehicle = player:GetVehicle()
   if vehicle.VehicleTable then
		player:GetVehicle():EmitSound("/beepbeep1.wav", 100, 100) 
   end
end
end
concommand.Add( "HonkHorn", HonkHorn )


local function SetPlayerInts( ply )
	ply.canuse = true
	ply.nextHyd = CurTime() + .5
end
hook.Add("PlayerSpawn", "ghtrshstrhtsrhtr", SetPlayerInts)

function ChooseSeat( ply, car )
	if ply:InVehicle() then
		ply.canuse = false
		timer.Simple(2, function() ply.canuse = true end)
		return true
	end
	
	if (car:IsVehicle() && IsValid(car:GetDriver()) && ply.canuse) then
	ply.canuse = false
	timer.Simple(2, function() ply.canuse = true end)
	
		local distancetable = {}
	
		for k, v in pairs(ents.FindInSphere(ply:GetPos(), 100 )) do
			if v:GetClass() == "prop_vehicle_prisoner_pod" && IsValid( v ) && car != v && v.locked == false then
				if !(IsOnCar( v, car )) then continue end
				local dtable = {
					seat = v,
					distance = v:GetPos():Distance( ply:GetPos() )
				}
				table.insert( distancetable, dtable ) 
			end
		end
		
		
		local maxdist = 500
		local nearestseat = 1
		local found = false
		for k, v in pairs( distancetable ) do
			if v.distance < maxdist then
				maxdist = v.distance
				nearestseat = k
				found = true
			end
		end
		
		
		if !(found) then return false end
		--if !(IsCarFriend( car:GetDriver(), ply )) then return end
		
		ply:EnterVehicle( distancetable[nearestseat].seat )
	else
		return true
	end
	
end
hook.Add("PlayerUse", "passengerseatenter", ChooseSeat)

local function FlipCar( ply )
	local pos = ply:EyePos()
	local tracedata = {}
	tracedata.start = pos
	tracedata.endpos = pos+(ply:GetForward()*450)
	tracedata.filter = ply
	local tr = util.TraceLine(tracedata)
	
	if tr.Entity:IsVehicle() && !(tr.Entity:GetClass() == "prop_vehicle_prisoner_pod") && tr.Entity.Owner == ply then
	local mass = tr.Entity:GetPhysicsObject():GetMass()
		tr.Entity:GetPhysicsObject():SetVelocity(tr.Entity:GetUp()*-(mass/2) + tr.Entity:GetRight()*5)
	end
end
AddChatCommand("/flip", FlipCar)
AddChatCommand("!flip", FlipCar)

local function catchHyd ( Player )
	if (Player.nextHyd && Player.nextHyd > CurTime()) then return end
	if (!Player:InVehicle()) then return end
	
	local vehicleTable = Player:GetVehicle().VehicleTable
	local owner = Player:GetVehicle().Owner
	
	if (!vehicleTable) then return end
	
	if !(owner:IsUserGroup("donator") or owner:IsAdmin()) then return end
		
	Player:GetVehicle():GetPhysicsObject():ApplyForceCenter(Player:GetVehicle():GetUp() * Player:GetVehicle():GetPhysicsObject():GetMass() * 200)
	
	Player.nextHyd = CurTime() + .5
end
concommand.Add("hydr", catchHyd)

function IsOnCar( seat, car )
	local cons = constraint.GetAllConstrainedEntities( car )
	
	for k, v in pairs(cons) do
		if IsValid( v ) && v == seat then
			return true
		end
	end
	return false
end

local function FindExitPos( ply, veh )
	local fis = veh:GetPos() + Vector(0, 0, 55)
	
	if ply:VisibleVec( fis ) then
		ply:ExitVehicle()
		ply:SetPos( fis )
	else
		FindExitPos( ply, veh )
	end
end

local function RagIfInSpeed( ply, veh )
	local vehicleVel = veh:GetVelocity():Length()
	local vehicleConv = -1
	local terminal = 0
		   
	terminal = math.Clamp(vehicleVel/2000, 0, 1)
	vehicleConv = math.Round(vehicleVel / 10)
	
	if vehicleConv >=45 then
		local hp = ply:Health()
		
		ply:ExitVehicle()
		
		local nexthealth = hp - math.Round((vehicleConv/1.5))
	
		ply:SetNoDraw(true)
		for k, v in pairs(ply:GetWeapons()) do
			v:SetNoDraw(true)
		end
	
		local rag = ents.Create( "prop_ragdoll" )
		rag:SetModel( ply:GetModel() )
		rag:SetPos( ply:GetPos() )
		rag:SetAngles( ply:GetAngles() )
		rag:Spawn()
		rag:Activate()
		rag:GetPhysicsObject():SetVelocity( veh:GetPhysicsObject():GetVelocity()*(vehicleConv*3) )
		
		ply:Spectate( OBS_MODE_CHASE )
		ply:SpectateEntity( rag )
		ply:Lock()
		
		ply.ragweps = ply:GetWeapons()
		ply.ragteam = ply:Team()

		ply:StripWeapons()

		timer.Simple(3, function()
			ply:Spawn()
			ply:SetPos( rag:GetPos() + Vector(0,0,10) )
			ply:SetHealth( nexthealth )
			rag:Remove()
			ply:UnSpectate( )
			ply:UnLock()
			
			if ply:Team() == ply.ragteam then // Changeteam Exploit
				for k, v in pairs(ply.ragweps) do
					if ply:HasWeapon( v:GetClass() ) then continue end
					ply:Give( v:GetClass() )
				end
			end
			
			ply.ragweps = {}
			
			ply:SetNoDraw(false)
			for k, v in pairs(ply:GetWeapons()) do
				v:SetNoDraw(false)
			end
			
			if (ply:Health()) < 5 then
				ply:Kill()
			end
		
		end)
	end
end

hook.Add("CanExitVehicle", "PAS_ExitVehicle", function( veh, ply )
	
	RagIfInSpeed( ply, veh )
	
	// L+R
	if ply:VisibleVec( veh:LocalToWorld(Vector(80, 0, 5) )) then
		ply:ExitVehicle()
		ply:SetPos( veh:LocalToWorld(Vector(75, 0, 5) ))
		return false
	end
	
	if ply:VisibleVec( veh:LocalToWorld(Vector(-80, 0, 5) )) then
		ply:ExitVehicle()
		ply:SetPos( veh:LocalToWorld(Vector(-75, 0, 5) ))
		return false
	end
	
	GAMEMODE:Notify( ply, 1, 4, "OAK: Ash, this isn't the time to get out of the car!" )
	return false
end)